package com.music.note_android.ui.editor

import android.graphics.Canvas
import android.graphics.RectF
import java.util.concurrent.ConcurrentHashMap
import kotlin.math.max
import kotlin.math.min

/**
 * 画布管理器
 * 负责管理无限画布的渲染、坐标转换、笔画存储和撤销重做功能
 */
class CanvasManager {
    
    // 所有笔画的存储，使用ConcurrentHashMap保证线程安全
    private val strokes = ConcurrentHashMap<String, Stroke>()
    
    // 所有点绘画的存储
    private val pointDrawings = ConcurrentHashMap<String, PointDrawing>()
    
    // 笔画的绘制顺序列表
    private val strokeOrder = mutableListOf<String>()
    
    // 点绘画的绘制顺序列表
    private val pointDrawingOrder = mutableListOf<String>()
    
    // 撤销栈 - 存储被删除的笔画
    private val undoStack = mutableListOf<HistoryAction>()
    
    // 重做栈 - 存储被撤销的操作
    private val redoStack = mutableListOf<HistoryAction>()
    
    // 最大撤销步数
    private var maxUndoSteps = 30
    
    // 画布边界缓存
    private var cachedBounds: RectF? = null
    private var boundsDirty = true
    
    // 画布边界
    private val canvasBounds = RectF()
    
    // 分块渲染相关
    private val tileSize = 256f // 每个瓦片的大小（像素）
    private val visibleTiles = mutableSetOf<TileKey>()
    
    /**
     * 瓦片键，用于标识画布上的每个瓦片
     */
    private data class TileKey(val x: Int, val y: Int)
    
    /**
     * 生成唯一的笔画ID
     */
    private fun generateStrokeId(): String {
        return "stroke_${System.currentTimeMillis()}_${hashCode()}"
    }
    

    
    /**
     * 添加笔画到画布
     */
    fun addStroke(stroke: Stroke) {
        // 检查笔画是否有效
        if (stroke.isEmpty()) {
            return
        }
        
        // 添加到存储中
        strokes[stroke.id] = stroke
        strokeOrder.add(stroke.id)
        
        // 添加到历史记录
        addToHistory(CanvasAction.ADD_STROKE, stroke)
        
        // 清空重做栈
        redoStack.clear()
        
        // 标记边界需要重新计算
        boundsDirty = true
        
        // 更新可见瓦片
        updateVisibleTiles(stroke.getBounds())
        
        // 更新相关分块
        updateChunksForStroke(stroke)
    }
    
    /**
     * 添加点绘画到画布
     */
    fun addPointDrawing(pointDrawing: PointDrawing) {
        // 检查点绘画是否有效
        if (pointDrawing.points.isEmpty()) {
            return
        }
        
        // 添加到存储中
        pointDrawings[pointDrawing.id] = pointDrawing
        pointDrawingOrder.add(pointDrawing.id)
        
        // 添加到历史记录
        addToHistory(CanvasAction.ADD_POINT_DRAWING, null, null, pointDrawing)
        
        // 清空重做栈
        redoStack.clear()
        
        // 标记边界需要重新计算
        boundsDirty = true
        
        // 更新可见瓦片
        updateVisibleTiles(pointDrawing.getBounds())
        
        // 更新相关分块
        updateChunksForPointDrawing(pointDrawing)
    }
    
    /**
     * 移除指定的笔画
     */
    fun removeStroke(strokeId: String) {
        val stroke = strokes[strokeId] ?: return
        
        // 从存储中移除
        strokes.remove(strokeId)
        strokeOrder.remove(strokeId)
        
        // 添加到历史记录
        addToHistory(CanvasAction.REMOVE_STROKE, stroke)
        
        // 清空重做栈
        redoStack.clear()
        
        // 标记边界需要重新计算
        boundsDirty = true
        
        // 更新相关分块
        updateChunksForStroke(stroke)
    }
    
    /**
     * 获取指定区域内的所有笔画
     */
    fun getStrokesInBounds(bounds: RectF): List<Stroke> {
        return strokeOrder.mapNotNull { strokeId ->
            strokes[strokeId]?.let { stroke ->
                if (RectF.intersects(stroke.getBounds(), bounds)) {
                    stroke
                } else {
                    null
                }
            }
        }
    }
    
    /**
     * 获取所有笔画
     */
    fun getAllStrokes(): List<Stroke> {
        return strokeOrder.mapNotNull { strokeId -> strokes[strokeId] }
    }
    
    /**
     * 获取所有点绘画
     */
    fun getAllPointDrawings(): List<PointDrawing> {
        return pointDrawingOrder.mapNotNull { pointDrawingId -> pointDrawings[pointDrawingId] }
    }
    
    /**
     * 获取画布的内容边界
     */
    fun getContentBounds(): RectF {
        if (!boundsDirty && cachedBounds != null) {
            return cachedBounds!!
        }
        
        if (strokes.isEmpty()) {
            cachedBounds = RectF(0f, 0f, 0f, 0f)
        } else {
            var minX = Float.MAX_VALUE
            var minY = Float.MAX_VALUE
            var maxX = Float.MIN_VALUE
            var maxY = Float.MIN_VALUE
            
            strokes.values.forEach { stroke ->
                val bounds = stroke.getBounds()
                minX = min(minX, bounds.left)
                minY = min(minY, bounds.top)
                maxX = max(maxX, bounds.right)
                maxY = max(maxY, bounds.bottom)
            }
            
            cachedBounds = RectF(minX, minY, maxX, maxY)
        }
        
        boundsDirty = false
        return cachedBounds!!
    }
    
    /**
     * 获取指定画布区域的可见边界
     */
    fun getVisibleBounds(canvas: Canvas): RectF {
        val clipBounds = canvas.clipBounds
        return RectF(clipBounds)
    }
    
    /**
     * 更新可见瓦片
     */
    private fun updateVisibleTiles(bounds: RectF) {
        val startTileX = (bounds.left / tileSize).toInt()
        val startTileY = (bounds.top / tileSize).toInt()
        val endTileX = (bounds.right / tileSize).toInt()
        val endTileY = (bounds.bottom / tileSize).toInt()
        
        for (x in startTileX..endTileX) {
            for (y in startTileY..endTileY) {
                visibleTiles.add(TileKey(x, y))
            }
        }
    }
    
    /**
     * 检查指定点是否有笔画
     */
    fun hasStrokeAt(x: Float, y: Float, tolerance: Float = 5f): Stroke? {
        // 从最新的笔画开始检查（后绘制的在上层）
        for (i in strokeOrder.size - 1 downTo 0) {
            val strokeId = strokeOrder[i]
            val stroke = strokes[strokeId] ?: continue
            
            if (stroke.containsPoint(x, y, tolerance)) {
                return stroke
            }
        }
        return null
    }
    
    /**
     * 擦除指定区域的笔画
     */
    fun eraseAt(x: Float, y: Float, eraserSize: Float): List<String> {
        val erasedStrokes = mutableListOf<String>()
        val tolerance = eraserSize / 2f
        
        // 查找需要擦除的笔画
        strokeOrder.forEach { strokeId ->
            val stroke = strokes[strokeId] ?: return@forEach
            
            if (stroke.containsPoint(x, y, tolerance)) {
                erasedStrokes.add(strokeId)
            }
        }
        
        // 移除被擦除的笔画
        erasedStrokes.forEach { strokeId ->
            removeStroke(strokeId)
        }
        
        return erasedStrokes
    }
    
    /**
     * 撤销最后一次操作
     */
    fun undo(): Boolean {
        if (undoStack.isEmpty()) {
            return false
        }
        
        val action = undoStack.removeLastOrNull() ?: return false
        
        when (action.type) {
            CanvasAction.ADD_STROKE -> {
                // 撤销添加操作：移除笔画
                val stroke = action.stroke!!
                strokes.remove(stroke.id)
                strokeOrder.remove(stroke.id)
                redoStack.add(action)
            }
            CanvasAction.REMOVE_STROKE -> {
                // 撤销移除操作：重新添加笔画
                val stroke = action.stroke!!
                strokes[stroke.id] = stroke
                strokeOrder.add(stroke.id)
                redoStack.add(action)
            }
            CanvasAction.ADD_POINT_DRAWING -> {
                // 撤销添加点绘画操作：移除点绘画
                val pointDrawing = action.pointDrawing!!
                pointDrawings.remove(pointDrawing.id)
                pointDrawingOrder.remove(pointDrawing.id)
                redoStack.add(action)
            }
            CanvasAction.REMOVE_POINT_DRAWING -> {
                // 撤销移除点绘画操作：重新添加点绘画
                val pointDrawing = action.pointDrawing!!
                pointDrawings[pointDrawing.id] = pointDrawing
                pointDrawingOrder.add(pointDrawing.id)
                redoStack.add(action)
            }
            CanvasAction.CLEAR_CANVAS -> {
                // 撤销清空操作：恢复所有笔画和点绘画
                action.strokes?.forEach { stroke ->
                    strokes[stroke.id] = stroke
                    strokeOrder.add(stroke.id)
                }
                action.pointDrawings?.forEach { pointDrawing ->
                    pointDrawings[pointDrawing.id] = pointDrawing
                    pointDrawingOrder.add(pointDrawing.id)
                }
                redoStack.add(action)
            }
        }
        
        boundsDirty = true
        return true
    }
    
    /**
     * 重做最后一次撤销的操作
     */
    fun redo(): Boolean {
        if (redoStack.isEmpty()) {
            return false
        }
        
        val action = redoStack.removeLastOrNull() ?: return false
        
        when (action.type) {
            CanvasAction.ADD_STROKE -> {
                // 重做添加操作：重新添加笔画
                val stroke = action.stroke!!
                strokes[stroke.id] = stroke
                strokeOrder.add(stroke.id)
                undoStack.add(action)
            }
            CanvasAction.REMOVE_STROKE -> {
                // 重做移除操作：重新移除笔画
                val stroke = action.stroke!!
                strokes.remove(stroke.id)
                strokeOrder.remove(stroke.id)
                undoStack.add(action)
            }
            CanvasAction.ADD_POINT_DRAWING -> {
                // 重做添加点绘画操作：重新添加点绘画
                val pointDrawing = action.pointDrawing!!
                pointDrawings[pointDrawing.id] = pointDrawing
                pointDrawingOrder.add(pointDrawing.id)
                undoStack.add(action)
            }
            CanvasAction.REMOVE_POINT_DRAWING -> {
                // 重做移除点绘画操作：重新移除点绘画
                val pointDrawing = action.pointDrawing!!
                pointDrawings.remove(pointDrawing.id)
                pointDrawingOrder.remove(pointDrawing.id)
                undoStack.add(action)
            }
            CanvasAction.CLEAR_CANVAS -> {
                // 重做清空操作：重新清空画布
                strokes.clear()
                strokeOrder.clear()
                pointDrawings.clear()
                pointDrawingOrder.clear()
                undoStack.add(action)
            }
        }
        
        boundsDirty = true
        return true
    }
    
    /**
     * 检查是否可以撤销
     */
    fun canUndo(): Boolean {
        return undoStack.isNotEmpty()
    }
    
    /**
     * 检查是否可以重做
     */
    fun canRedo(): Boolean {
        return redoStack.isNotEmpty()
    }
    
    /**
     * 获取撤销历史数量
     */
    fun getUndoCount(): Int {
        return undoStack.size
    }
    
    /**
     * 获取重做历史数量
     */
    fun getRedoCount(): Int {
        return redoStack.size
    }
    
    /**
     * 清空撤销重做历史
     */
    fun clearHistory() {
        undoStack.clear()
        redoStack.clear()
    }
    
    /**
     * 清空画布
     */
    fun clear() {
        if (strokes.isNotEmpty() || pointDrawings.isNotEmpty()) {
            // 保存当前状态用于撤销
            val currentStrokes = getAllStrokes()
            val currentPointDrawings = getAllPointDrawings()
            addToHistory(
                CanvasAction.CLEAR_CANVAS, 
                null, 
                currentStrokes,
                null,
                currentPointDrawings
            )
            
            // 清空所有数据
            strokes.clear()
            strokeOrder.clear()
            pointDrawings.clear()
            pointDrawingOrder.clear()
            redoStack.clear()
            
            // 清空所有分块
            visibleTiles.clear()
            
            boundsDirty = true
        }
    }
    

    
    /**
     * 设置最大撤销步数
     */
    fun setMaxUndoSteps(steps: Int) {
        maxUndoSteps = steps.coerceIn(1, 100)
        
        // 如果当前撤销栈超过限制，移除多余的项
        while (undoStack.size > maxUndoSteps) {
            undoStack.removeFirstOrNull()
        }
    }
    
    /**
     * 获取当前笔画数量
     */
    fun getStrokeCount(): Int {
        return strokes.size
    }
    
    /**
     * 获取撤销栈大小
     */
    fun getUndoStackSize(): Int {
        return undoStack.size
    }
    
    /**
     * 获取重做栈大小
     */
    fun getRedoStackSize(): Int {
        return redoStack.size
    }
    
    /**
     * 获取画布统计信息
     */
    fun getStatistics(): CanvasStatistics {
        val bounds = getContentBounds()
        var totalPoints = 0
        var totalLength = 0f
        
        strokes.values.forEach { stroke ->
            totalPoints += stroke.points.size
            totalLength += stroke.getLength()
        }
        
        return CanvasStatistics(
            strokeCount = strokes.size,
            totalPoints = totalPoints,
            totalLength = totalLength,
            canvasWidth = bounds.width(),
            canvasHeight = bounds.height(),
            undoSteps = undoStack.size,
            redoSteps = redoStack.size
        )
    }
    
    /**
     * 画布统计信息数据类
     */
    data class CanvasStatistics(
        val strokeCount: Int,
        val totalPoints: Int,
        val totalLength: Float,
        val canvasWidth: Float,
        val canvasHeight: Float,
        val undoSteps: Int,
        val redoSteps: Int
    )
    
    /**
     * 更新笔画相关的分块
     */
    private fun updateChunksForStroke(stroke: Stroke) {
        val bounds = stroke.getBounds()
        updateVisibleTiles(bounds)
    }
    
    /**
     * 更新点绘画相关的分块
     */
    private fun updateChunksForPointDrawing(pointDrawing: PointDrawing) {
        val bounds = pointDrawing.getBounds()
        updateVisibleTiles(bounds)
    }
    
    /**
     * 获取指定边界内的分块
     */
    private fun getChunksInBounds(bounds: RectF): Set<TileKey> {
        val chunks = mutableSetOf<TileKey>()
        val startTileX = (bounds.left / tileSize).toInt()
        val startTileY = (bounds.top / tileSize).toInt()
        val endTileX = (bounds.right / tileSize).toInt()
        val endTileY = (bounds.bottom / tileSize).toInt()
        
        for (x in startTileX..endTileX) {
            for (y in startTileY..endTileY) {
                chunks.add(TileKey(x, y))
            }
        }
        
        return chunks
    }
    
    /**
      * 获取可见区域内的笔画（基于分块优化）
      */
     fun getVisibleStrokes(viewBounds: RectF): List<Stroke> {
         // 获取可见区域涉及的分块
         val visibleChunks = getChunksInBounds(viewBounds)
         
         // 收集可见分块中的笔画
         return strokeOrder.mapNotNull { strokeId ->
             strokes[strokeId]?.let { stroke ->
                 val strokeBounds = stroke.getBounds()
                 if (RectF.intersects(strokeBounds, viewBounds)) {
                     stroke
                 } else {
                     null
                 }
             }
         }
     }
     
     /**
      * 添加到历史记录
      */
     private fun addToHistory(
         type: CanvasAction, 
         stroke: Stroke? = null, 
         strokes: List<Stroke>? = null,
         pointDrawing: PointDrawing? = null,
         pointDrawings: List<PointDrawing>? = null
     ) {
         val action = HistoryAction(type, stroke, strokes, pointDrawing, pointDrawings)
         undoStack.add(action)
         
         // 限制撤销栈大小
         if (undoStack.size > maxUndoSteps) {
             undoStack.removeAt(0)
         }
         
         // 清空重做栈
         redoStack.clear()
      }
     
     /**
      * 内部添加笔画方法（不记录历史）
      */
     private fun addStrokeInternal(stroke: Stroke) {
         val strokeId = generateStrokeId()
         strokes[strokeId] = stroke
         strokeOrder.add(strokeId)
         
         // 更新可见瓦片
         updateVisibleTiles(stroke.getBounds())
         
         // 更新相关分块
         updateChunksForStroke(stroke)
         
         // 更新画布边界
         updateCanvasBounds(stroke)
     }
     
     /**
      * 内部移除笔画方法（不记录历史）
      */
     private fun removeStrokeInternal(stroke: Stroke) {
         val strokeId = strokeOrder.find { strokes[it] == stroke }
         if (strokeId != null) {
             strokes.remove(strokeId)
             strokeOrder.remove(strokeId)
             
             // 更新相关分块
             updateChunksForStroke(stroke)
             
             // 重新计算画布边界
             recalculateCanvasBounds()
         }
     }
     
     /**
      * 重新计算画布边界
      */
     private fun recalculateCanvasBounds() {
         canvasBounds.setEmpty()
         strokes.values.forEach { stroke ->
             val strokeBounds = stroke.getBounds()
             if (canvasBounds.isEmpty) {
                 canvasBounds.set(strokeBounds)
             } else {
                 canvasBounds.union(strokeBounds)
             }
         }
     }
     
     /**
      * 更新画布边界
      */
     private fun updateCanvasBounds(stroke: Stroke) {
         val strokeBounds = stroke.getBounds()
         if (canvasBounds.isEmpty) {
             canvasBounds.set(strokeBounds)
         } else {
             canvasBounds.union(strokeBounds)
         }
     }
     
     /**
      * 画布操作类型
      */
     enum class CanvasAction {
         ADD_STROKE,
         REMOVE_STROKE,
         ADD_POINT_DRAWING,
         REMOVE_POINT_DRAWING,
         CLEAR_CANVAS
     }
     
     /**
     * 历史操作记录
     */
    private data class HistoryAction(
        val type: CanvasAction,
        val stroke: Stroke?,
        val strokes: List<Stroke>? = null,
        val pointDrawing: PointDrawing? = null,
        val pointDrawings: List<PointDrawing>? = null
    )
    
    /**
     * 历史信息数据类
     */
    data class HistoryInfo(
        val undoCount: Int,
        val redoCount: Int,
        val canUndo: Boolean,
        val canRedo: Boolean,
        val maxHistorySize: Int
    )
}